' you can modify the filter for your own needs.
' in our case, we only select the groups that end 
' in "-mail", as those are our mailing lists
' there are other ways to determine the type of
' list but they're not shown here.

' this script flattens nested lists and 
' de-dupes the membership

' replace some.org below with your org's dn.

' this dumps a text file that probably needs to be
' modified to work with other scripts.

Const ADS_SCOPE_SUBTREE = 2

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = _
    "SELECT mail,adspath FROM 'LDAP://dc=some,dc=org' WHERE objectCategory='group'" & _
        "AND Name = '*-mail'" 
Set objRecordSet = objCommand.Execute

'dump the flattened distribution groups

objRecordSet.MoveFirst
Do Until objRecordSet.EOF

    set dicSeenGroupMember = CreateObject("Scripting.Dictionary")
    wscript.echo
    wscript.echo "*****"
    wscript.echo objRecordSet.Fields("mail")  & ": "
    DumpMembers objRecordSet.Fields("adspath"), dicSeenGroupMember

    objRecordSet.MoveNext
Loop

'go back and print the list of all the nested groups for sanity

objRecordSet.MoveFirst
Do Until objRecordSet.EOF

    wscript.echo
    wscript.echo "*****"
    wscript.echo objRecordSet.Fields("mail")
    set dicSeenGroupMember = CreateObject("Scripting.Dictionary")
    strSpaces  = " "
    DisplayMembers objRecordSet.Fields("adspath"), strSpaces, dicSeenGroupMember

    objRecordSet.MoveNext
Loop

Function DumpMembers (strGroupADsPath, dicSeenGroupMember)

   set objGroup = GetObject(strGroupADsPath)
   for each objMember In objGroup.Members
      if not dicSeenGroupMember.Exists(objMember.ADsPath) then

          if not objMember.Class = "group" then
              Wscript.Echo objMember.mail & ", "
          end if

          dicSeenGroupMember.Add objMember.ADsPath, 1

          if objMember.Class = "group" then
            DumpMembers objMember.ADsPath, dicSeenGroupMember
          end if

      end if
   next

End Function


strSpaces  = " "

Function DisplayMembers ( strGroupADsPath, strSpaces, dicSeenGroupMember)

   set objGroup = GetObject(strGroupADsPath)
   Wscript.Echo "Members of " & objGroup.Name & ":"
   for each objMember In objGroup.Members
      Wscript.Echo strSpaces & objMember.Name
      if objMember.Class = "group" then
         if dicSeenGroupMember.Exists(objMember.ADsPath) then
            Wscript.Echo strSpaces & "   ^ already seen group member " & _
                                     "(stopping to avoid loop)"
         else
            dicSeenGroupMember.Add objMember.ADsPath, 1
            DisplayMembers objMember.ADsPath, strSpaces & " ", _
                           dicSeenGroupMember
         end if
      end if
   next

End Function
